home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Tools - Objects / MacApp / MacApp 3.0a2 / Libraries / UMemory.cp < prev    next >
Encoding:
Text File  |  1991-05-01  |  43.5 KB  |  1,927 lines  |  [TEXT/MPS ]

  1. /* UMemory.cp */
  2. /* Copyright © 1985-1991 by Apple Computer, Inc.  All rights reserved. */
  3.  
  4. #ifndef __UMEMEORY__
  5. #include "UMemory.h"
  6. #endif
  7.  
  8. #ifndef __STDIO__
  9. #include <StdIo.h>
  10. #endif
  11.  
  12. #ifndef __UFAILURE__
  13. #include "UFailure.h"
  14. #endif
  15.  
  16. #ifndef __MEMORY__
  17. #include "Memory.h"
  18. #endif
  19.  
  20. #ifndef __TEXTEDIT__
  21. #include "Textedit.h"
  22. #endif
  23.  
  24. #ifndef __OSUTILS__
  25. #include "OSUtils.h"
  26. #endif
  27.  
  28. #ifndef __UMACAPPUTILITIES__
  29. #include "UMacAppUtilities.h"
  30. #endif
  31.  
  32. #ifndef __SYSEQU__
  33. #include "SysEqu.h"
  34. #endif
  35.  
  36. #ifndef __TRAPS__
  37. #include "Traps.h"
  38. #endif
  39.  
  40. #ifndef __DEVICES__
  41. #include "Devices.h"
  42. #endif
  43.  
  44. #ifndef __ULOMEM__
  45. #include "ULoMem.h"
  46. #endif
  47.  
  48. #ifndef __TOOLUTILS__
  49. #include "ToolUtils.h"
  50. #endif
  51.  
  52. #ifndef __RESOURCES__
  53. #include "Resources.h"
  54. #endif
  55.  
  56. #ifndef __PACKAGES__
  57. #include "Packages.h"
  58. #endif
  59.  
  60. #ifndef __ERRORS__
  61. #include "Errors.h"
  62. #endif
  63.  
  64. #ifndef __UDEBUG__
  65. #include "UDebug.h"
  66. #endif
  67.  
  68. #ifndef __SEGLOAD__
  69. #include "SegLoad.h"
  70. #endif
  71.  
  72. #ifndef __RTLIB__
  73. #include "RtLib.h"
  74. #endif
  75.  
  76. #if qDebugMsg
  77. #ifndef __STDIO__
  78. #include <StdIO.h>
  79. #endif
  80. #endif
  81.  
  82. #if !qDebugTheDebugger
  83. #pragma W+
  84. #pragma R-
  85. #pragma Init-
  86. #pragma OV-
  87. #endif
  88.  
  89. // Globals to this module and externally available.
  90. Size gMaxLockedRsrc;
  91. #if qDebug
  92. Boolean gMemMgtBreak = FALSE;
  93. Boolean gRsrcReport = FALSE;
  94. Boolean gSegReport = FALSE;
  95. #endif
  96.  
  97. HandleListHandle gSysMemList;
  98. HandleListHandle gApp1MemList;
  99. HandleListHandle gApp2MemList;
  100. short gCodeRefNum;
  101. HandleListHandle gCodeSegs;
  102. BoolListHandle gIsLoadedSeg;
  103. BoolListHandle gIsResidentSeg;
  104.  
  105. // Static, globals to this module. Many of these are static by convention, but we don't
  106. // declare them as static because people may want to examine them.
  107.  
  108. Boolean gUnloadAllSegs;
  109. ProcPtr gGZPurgeNotify;
  110. LongListHandle pSegSize;
  111. Handle pCodeReserve;
  112. Handle pMemReserve;
  113. Boolean pOKCodeReserve;
  114. Boolean pPermAllocation;
  115. Boolean pReserveExists;
  116.  
  117. #if qDebug
  118. long pReserveShortfall;
  119. #endif
  120.  
  121. Size pSzCodeReserve;
  122. Size pSzMemReserve;
  123. TrapPatch pSegLoadPatch;
  124. short pOldResFile;
  125. Boolean pLoadSegCalledFromOwnApp;
  126. short pMaxSegNum;
  127.  
  128. // local private globals
  129. static Boolean pDuringGrowZone;
  130. static SegLoadHdlrPtr oldPreLoadHandler;
  131. static SegLoadHdlrPtr oldPostLoadHandler;
  132.  
  133. // Function prototypes for some routines in this module.
  134.  
  135. pascal long GrowZoneProc(Size needed);
  136.  
  137. // Function prototypes for the routines in UMemory.a
  138.  
  139. pascal void ALoadMacAppSeg(void);
  140.  
  141. /* LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
  142.   LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
  143.   procedure pointer, because no args are declared */
  144.  
  145. // Other function prototypes that are externally defined.
  146.  
  147. typedef pascal void( *DoToFrameType)(long,
  148.                                      long,
  149.                                      long,
  150.                                      long,
  151.                                      void *);
  152.  
  153. pascal void EachFrameDo(long calleeFrame,
  154.                         long ppc,
  155.                         DoToFrameType DoToFrame,
  156.                         void *scopeLink);
  157.  
  158. pascal void CallNotify(Handle h,
  159.                        ProcPtr routine) = {
  160.                                            0x205F, 0x4E90};// MOVE.L (A7)+,A0; JSR (A0) 
  161.  
  162. pascal short CallHandler(RTState* state,
  163.                          SegLoadHdlrPtr routine) = {
  164.                                              0x205F, 0x4E90};// MOVE.L (A7)+,A0; JSR (A0) 
  165.  
  166. //--------------------------------------------------------------------------------------------------
  167.  
  168. // These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
  169. // problem of multiple open resource maps in general); when running under the THINK™ environment,
  170. // CODE resources are not found in the same resource file as other application resources, so a
  171. // UseResFile call needs to be made to bring the project resource file into the search path.
  172. // "gCodeRefNum" is set up at initialization time.
  173. // !!! A much more general solution to "the resource problem" appears to be warranted.
  174.  
  175. //--------------------------------------------------------------------------------------------------
  176. #pragma segment MAMemoryRes
  177.  
  178. pascal Handle MAGet1Resource(ResType rType,
  179.                              short rID)
  180. {
  181.     short oldResFile;
  182.     Handle resource;
  183.  
  184.     oldResFile = MAUseResFile(gCodeRefNum);
  185.     resource = Get1Resource(rType, rID);
  186.     MAUseResFile(oldResFile);
  187.  
  188.     return resource;
  189. }
  190.  
  191. //--------------------------------------------------------------------------------------------------
  192. #pragma segment MAMemoryRes
  193.  
  194. pascal Handle MAGet1NamedResource(ResType rType,
  195.                                   const Str255 &name)
  196. {
  197.     short oldResFile;
  198.     Handle namedResource;
  199.  
  200.     oldResFile = MAUseResFile(gCodeRefNum);
  201.     namedResource = Get1NamedResource(rType, name);
  202.     MAUseResFile(oldResFile);
  203.  
  204.     return namedResource;
  205. }
  206.  
  207. //--------------------------------------------------------------------------------------------------
  208. #pragma segment MAMemoryRes
  209.  
  210. pascal Handle MAGet1IndResource(ResType rType,
  211.                                 short index)
  212. {
  213.     short oldResFile;
  214.     Handle indResource;
  215.  
  216.     oldResFile = MAUseResFile(gCodeRefNum);
  217.     indResource = Get1IndResource(rType, index);
  218.     MAUseResFile(oldResFile);
  219.  
  220.     return indResource;
  221. }
  222.  
  223. //--------------------------------------------------------------------------------------------------
  224. #pragma segment MAMemoryRes
  225.  
  226. pascal short MACount1Resources(ResType rType)
  227. {
  228.     short oldResFile;
  229.     short resourceCnt;
  230.  
  231.     oldResFile = MAUseResFile(gCodeRefNum);
  232.     resourceCnt = Count1Resources(rType);
  233.     MAUseResFile(oldResFile);
  234.  
  235.     return resourceCnt;
  236. }
  237.  
  238. //--------------------------------------------------------------------------------------------------
  239. #pragma segment MAMemoryRes
  240.  
  241. pascal Handle MAGetResource(ResType rType,
  242.                             short rID)
  243. {
  244.     Handle h;
  245.     short oldResFile;
  246.  
  247.     oldResFile = MAUseResFile(gCodeRefNum);
  248.     h = GetResource(rType, rID);
  249.     MAUseResFile(oldResFile);
  250.  
  251.     return HomeResFile(h) != gCodeRefNum ? NULL : h;
  252. }
  253.  
  254. //--------------------------------------------------------------------------------------------------
  255. #pragma segment MAMemoryRes
  256.  
  257. pascal Handle MAGetNamedResource(ResType rType,
  258.                                  const Str255 &name)
  259. {
  260.     Handle h;
  261.     short oldResFile;
  262.  
  263.     oldResFile = MAUseResFile(gCodeRefNum);
  264.     h = GetNamedResource(rType, name);
  265.     MAUseResFile(oldResFile);
  266.  
  267.     return HomeResFile(h) != gCodeRefNum ? NULL : h;
  268. }
  269.  
  270. //--------------------------------------------------------------------------------------------------
  271. #pragma segment MAMemoryRes
  272.  
  273. pascal Handle MAGetIndResource(ResType rType,
  274.                                short index)
  275. {
  276.     Handle h;
  277.     short oldResFile;
  278.  
  279.     oldResFile = MAUseResFile(gCodeRefNum);
  280.     h = GetIndResource(rType, index);
  281.     MAUseResFile(oldResFile);
  282.  
  283.     return HomeResFile(h) != gCodeRefNum ? NULL : h;
  284. }
  285.  
  286. //--------------------------------------------------------------------------------------------------
  287. #pragma segment MAMemoryRes
  288.  
  289. pascal short MACountResources(ResType rType)
  290. {
  291.     short oldResFile;
  292.     short resourceCnt;
  293.  
  294.     oldResFile = MAUseResFile(gCodeRefNum);
  295.     resourceCnt = CountResources(rType);
  296.     MAUseResFile(oldResFile);
  297.  
  298.     return resourceCnt;
  299. }
  300.  
  301. //--------------------------------------------------------------------------------------------------
  302. #pragma segment MAMemoryRes
  303.  
  304. Handle GetSegResource(short segNum)
  305. {
  306.     return MAGet1Resource(kCode, segNum);
  307. }
  308.  
  309. //--------------------------------------------------------------------------------------------------
  310. #pragma segment MAMiniInit
  311.  
  312. pascal void AddAllRsrc(ResType rType,
  313.                        HandleListHandle toList)
  314. {
  315.     Boolean oldResLoad;
  316.     short i, 
  317.     nResources, 
  318.     theID;
  319.     Handle h;
  320.     ResType theType;
  321.     Str255 theName;
  322.  
  323.     oldResLoad = GetResLoad();
  324.     SetResLoad(FALSE);
  325.  
  326.     nResources = CountResources(rType);
  327.     for (i = 1; i <= nResources; ++i)
  328.     {
  329.         h = GetIndResource(rType, i);
  330.         GetResInfo(h, theID, theType, theName);
  331.  
  332.         /* If there is a ROM resource for this type and ID, don't put it
  333.           on the list. */
  334.  
  335.         UseROMMap(FALSE);
  336.         h = GetResource(rType, theID);
  337.         UseROMMap(FALSE);
  338.         if (HomeResFile(h) != 1)
  339.             AddHandle(h, toList);
  340.     }
  341.  
  342.     SetResLoad(oldResLoad);
  343. }
  344.  
  345. //--------------------------------------------------------------------------------------------------
  346. #pragma segment MAMiniInit
  347.  
  348. pascal void AddHandle(Handle h,
  349.                       HandleListHandle toList)
  350. {
  351.     long offset;
  352.  
  353.     offset = Munger((Handle)toList, 0, NULL, 0, (Ptr) & h, 4);
  354.     FailMemError();
  355. }
  356.  
  357. //--------------------------------------------------------------------------------------------------
  358. #pragma segment MAMiniInit
  359.  
  360. pascal long AddSegSizes(Handle segRsrc)
  361. {
  362.     SignedByte savedState;
  363.     SignedBytePtr p;
  364.     Boolean oldResLoad;
  365.     register long total;
  366.     Handle seg;
  367.     short i;
  368.     Str255 s;
  369.  
  370.     savedState = LockHandleHigh(segRsrc);
  371.  
  372.     oldResLoad = GetResLoad();
  373.     SetResLoad(FALSE);
  374.  
  375.     p = (SignedBytePtr) * segRsrc;
  376.     i = *((IntegerPtr)p);
  377.     p += 2;
  378.  
  379.     total = 0;
  380.  
  381.     for (; i > 0; i--, p += *p + 1)
  382.     {
  383.         BlockMove((Ptr)p, (Ptr) & s, *p + 1);
  384.         seg = MAGet1NamedResource(kCode, s);
  385.         if (seg)
  386.             total += SizeResource(seg) + 8;
  387.     }
  388.  
  389.     SetResLoad(oldResLoad);
  390.     HSetState(segRsrc, savedState);
  391.  
  392.     return total;
  393. }
  394.  
  395. //--------------------------------------------------------------------------------------------------
  396. #pragma segment MAMemoryRes
  397. #pragma Push
  398. #if qTrace
  399. #pragma D+
  400. #endif
  401.  
  402. Boolean IsHandleEligible(Handle h)
  403. {
  404.     if (h == NULL)
  405.         return FALSE;                            // Thanks Pillar! 
  406.     else if (IsHandlePurged(h))
  407.         return FALSE;
  408.     else
  409.         return (h != GetGZMoveHnd()) && (h != GetGZRootHnd());
  410. }
  411. #pragma Pop
  412.  
  413. //--------------------------------------------------------------------------------------------------
  414. #pragma segment MAMemoryRes
  415. #pragma Push
  416. #if qTrace
  417. #pragma D+
  418. #endif
  419.  
  420. void BuildCodeReserve(Size allocLim,
  421.                              Boolean fromGZ)
  422. {
  423.     static const short initVal = 0xF7;
  424.  
  425.     Size needed,  avail;
  426.     Handle canPurge = 0;
  427. #if qDebug
  428.     Size theSize;
  429. #endif
  430.  
  431.     pOKCodeReserve = TRUE;                        // default value 
  432.  
  433. #if qDebug
  434.     pReserveShortfall = 0;
  435.  
  436.     if (!pPermAllocation)
  437.         ProgramBreak("BuildCodeReserve called with pPermAllocation = FALSE");
  438. #endif
  439.  
  440.     if (!pReserveExists)
  441.     {
  442.         pReserveExists = TRUE;                    // default value 
  443.  
  444.         // free the current code reserve 
  445.         if (IsHandleEligible(pCodeReserve))
  446.             EmptyHandle(pCodeReserve);
  447.  
  448.         // compute amt actually needed 
  449.         needed = Min(pSzCodeReserve - TotalTempSize(FALSE, canPurge) - 8, allocLim);
  450.  
  451.         if (needed > 0)
  452.         {
  453.             // make as much memory available as possible 
  454.             if (IsHandleEligible(pMemReserve))
  455.                 EmptyHandle(pMemReserve);
  456.  
  457.             if (fromGZ)                            // Never purge or compact from GrowZone 
  458.                 avail = allocLim;
  459.             else
  460.                 {
  461.                 PurgeMem(needed);
  462.                 avail = CompactMem(needed);
  463.             }
  464.  
  465.             if (avail < needed)                    // could not get the whole reserve 
  466.             {
  467. #if qDebug
  468.                 pReserveShortfall = needed - avail;
  469. #endif
  470.  
  471.                 pOKCodeReserve = FALSE;
  472.                 pReserveExists = FALSE;
  473.  
  474.                 needed = avail;                    // get the most we can 
  475.             }
  476.  
  477.             if (!fromGZ && (IsHandlePurged(pCodeReserve) || IsHandleEligible(pCodeReserve)))
  478.                 ReallocHandle(pCodeReserve, needed);
  479. #if qDebug
  480.             theSize = GetHandleSize(pCodeReserve);
  481. #pragma Push
  482. #pragma R-
  483.             if (theSize != 0)
  484.                 BlockSet(*pCodeReserve, theSize, initVal);
  485. #pragma Pop
  486. #endif
  487.  
  488.             if (!IsHandlePurged(pCodeReserve))
  489.             {
  490.                 /* Large handles are almost as bad as nonrelocatable blocks.
  491.                   Try to get this guy out of the way, just in case.*/
  492.  
  493.                 if (!fromGZ)
  494.                     MoveHHi(pCodeReserve);
  495.             }
  496.         }
  497.     }
  498. }
  499. /*$Pop*/
  500.  
  501. //--------------------------------------------------------------------------------------------------
  502. #pragma segment MAMemoryRes
  503. #pragma Push
  504. #if qTrace
  505. #pragma D+
  506. #endif
  507.  
  508. pascal void BuildAllReserves()
  509.  
  510. {
  511.     static const short initVal = 0xF7;
  512.  
  513.     Boolean oldPerm;
  514. #if qDebug
  515.     Size theSize;
  516. #endif
  517.  
  518.     /* set the permanent flag to ensure that the code reserve is
  519.       actually allocated and not given up to the low space reserve */
  520.  
  521.     oldPerm = pPermAllocation;
  522.     pPermAllocation = TRUE;
  523.  
  524.     BuildCodeReserve(kGZMaxAlloc, FALSE);        // make sure code reserve is OK
  525.  
  526.     // reallocate the low space handle, if necessary
  527.  
  528.     if (IsHandlePurged(pMemReserve))
  529.     {
  530.         ReallocHandle(pMemReserve, pSzMemReserve);
  531. #if qDebug
  532.         theSize = GetHandleSize(pMemReserve);
  533. #pragma Push
  534. #pragma R-
  535.         if (theSize != 0)
  536.             BlockSet(*pMemReserve, theSize, initVal);
  537. #pragma Pop
  538. #endif
  539.  
  540.     }
  541.  
  542.     pPermAllocation = oldPerm;                    // reset the permanent flag 
  543. }
  544. #pragma Pop
  545.  
  546. //--------------------------------------------------------------------------------------------------
  547. #pragma segment MAMemoryRes
  548.  
  549. pascal Boolean CheckReserve()
  550. {
  551.     BuildAllReserves();
  552.     return pOKCodeReserve;
  553. }
  554.  
  555. //--------------------------------------------------------------------------------------------------
  556. #if qDebug
  557. #pragma segment MAMemoryRes
  558.  
  559. pascal void CheckRsrcUsage()
  560. {
  561.     long sz;
  562.     Handle h;
  563.     Str255 s;
  564.  
  565.     sz = TotalTempSize(TRUE, h);
  566.     if (sz > gMaxLockedRsrc)
  567.     {
  568.         gMaxLockedRsrc = sz;
  569.         if (gRsrcReport)
  570.         {
  571.             NumToString(gMaxLockedRsrc, s);
  572.             s = "  = New maximum resources usage: " + s + " =";
  573.             ProgramReport(s, gMemMgtBreak);
  574.         }
  575.     }
  576. }
  577. #endif
  578.  
  579. //--------------------------------------------------------------------------------------------------
  580. #if qDebug
  581. #pragma segment MADebug
  582.  
  583. pascal void DoChangeReserve(Boolean alter,
  584.                             Size &codeReserve,
  585.                             Size &codeShort,
  586.                             Size &lowSpaceReserve,
  587.                             Boolean &gotCode,
  588.                             Boolean &gotLowSpace)
  589. {
  590.     long x;
  591.     Str255 s;
  592.     char cS[10];
  593.  
  594.     if (alter)
  595.     {
  596.         fprintf(stderr, "code reserve size = %ld  ", pSzCodeReserve);
  597.         if (pOKCodeReserve)
  598.             fprintf(stderr, " (OK)\n");
  599.         else
  600.             fprintf(stderr, " (gone)\n");
  601.  
  602.         fprintf(stderr, "low space reserve size = %ld  ", pSzMemReserve);
  603.         if (!IsHandlePurged(pMemReserve))
  604.             fprintf(stderr, " (OK)\n");
  605.         else
  606.             fprintf(stderr, " (gone)\n");
  607.  
  608.         fprintf(stderr, "\n");
  609.  
  610.         fprintf(stderr, "New code reserve (-1 == no change): ");
  611.         fscanf(stdin, "%ld", &x);
  612.         if (x >= 0)
  613.             codeReserve = x;
  614.         else
  615.             codeReserve = pSzCodeReserve;
  616.  
  617.         fprintf(stderr, "New low space reserve (-1 == no change): ");
  618.         fscanf(stdin, "%ld", &x);
  619.         if (x >= 0)
  620.             lowSpaceReserve = x;
  621.         else
  622.             lowSpaceReserve = pSzMemReserve;
  623.  
  624.         fprintf(stderr, "Reset max resource usage (Y or N) [N]? ");
  625.         fscanf(stdin, "%s", cS);
  626.         s = cS;
  627.         if (!s.IsEmpty())
  628.         {
  629.             if ((s[1] == 'y') || (s[1] == 'Y'))
  630.                 gMaxLockedRsrc = 0;
  631.         }
  632.  
  633.         fprintf(stderr, "\n");
  634.  
  635.         SetReserveSize(codeReserve, lowSpaceReserve);
  636.     }
  637.     else
  638.         BuildAllReserves();
  639.  
  640.     codeReserve = pSzCodeReserve;
  641.     codeShort = pReserveShortfall;
  642.     lowSpaceReserve = pSzMemReserve;
  643.     gotCode = pOKCodeReserve;
  644.     gotLowSpace =!IsHandlePurged(pMemReserve);
  645. }
  646. #endif
  647.  
  648. //--------------------------------------------------------------------------------------------------
  649. #pragma segment MAMiniInit
  650.  
  651. /* Called from InitUMemory so that InitUMemory can be in the main segment
  652.   and this code can be in another (unloadable) segment. */
  653.  
  654. pascal void DoInitUMemory(Size &sizeTempReserve,
  655.                           Size &sizeLowSpaceReserve)
  656. {
  657.     struct Mem
  658.     {
  659.         long codeVal, lowSpaceVal, stackVal;
  660.     };
  661.  
  662.  
  663.     typedef Mem *MemPtr, 
  664.     **MemHandle;
  665.  
  666.     short i, 
  667.     rsrcCnt;
  668.     Boolean oldResLoad;
  669.     Handle seg,  h;
  670.     long stackTot;
  671.     short rsrcID;
  672.     ResType rsrcType;
  673.     Str255 rsrcName;
  674.     short lastRsrc;
  675.     short mainSegment,  utilitySegment;
  676.  
  677.     // Initialize memory management globals
  678.  
  679.     pPermAllocation = FALSE;
  680.     pMemReserve = NewHandle(0);
  681.     FailNIL(pMemReserve);
  682.  
  683.     pSzMemReserve = 0;
  684.     pCodeReserve = NewHandle(0);
  685.     FailNIL(pCodeReserve);
  686.  
  687.     pSzCodeReserve = 0;
  688.     gGZPurgeNotify = NULL;
  689.     pOKCodeReserve = TRUE;
  690.     pReserveExists = FALSE;
  691.  
  692.     gUnloadAllSegs = TRUE;
  693.  
  694.     gCodeRefNum = HomeResFile(GetResource(kCode, 1));/* Get homeresfile of "Main". It better be
  695.                                                   there!!*/
  696.     pMaxSegNum = 0;
  697.  
  698.     //###########################################
  699.     // No resource loading 
  700.  
  701.     oldResLoad = GetResLoad();
  702.     SetResLoad(FALSE);
  703.  
  704.     // Figure the highest segment number 
  705.     lastRsrc = MACount1Resources(kCode);
  706.  
  707.     /* some development systems may not have contiguous numbering of CODE segments.
  708.       try to be polite about handling it */
  709.  
  710.     for (i = 1; i <= lastRsrc; ++i)
  711.     {
  712.         seg = MAGet1IndResource(kCode, i);
  713.  
  714.         /* we only have an index… find the real resource ID and keep track
  715.           of the highest one */
  716.  
  717.         if (seg)
  718.         {
  719.             GetResInfo(seg, rsrcID, rsrcType, rsrcName);
  720.             pMaxSegNum = (short)Max(rsrcID, pMaxSegNum);
  721.         }
  722.     }
  723.  
  724.     SetResLoad(oldResLoad);                        // in case of failure 
  725.  
  726.     // Allocate the master segment lists.
  727.     gCodeSegs = (HandleListHandle)NewHandle(pMaxSegNum * sizeof(Handle));
  728.     FailNIL(gCodeSegs);
  729.  
  730.     gIsResidentSeg = (BoolListHandle)NewHandle(pMaxSegNum * sizeof(Boolean));
  731.     FailNIL(gIsResidentSeg);
  732.  
  733.     gIsLoadedSeg = (BoolListHandle)NewHandle(pMaxSegNum * sizeof(Boolean));
  734.     FailNIL(gIsLoadedSeg);
  735.  
  736.     /* (NOTE: assumes application doesn't change the CODE segment size at runtime
  737.       (a very safe assumption)). Used in GetSegFromPC. */
  738.  
  739.     pSegSize = (LongListHandle)NewHandle(pMaxSegNum * sizeof(long));
  740.     FailNIL(pSegSize);
  741.  
  742.     oldResLoad = GetResLoad();                    // OK, suppress segment loading again 
  743.     SetResLoad(FALSE);                            /* !!! Need an MAResLoad that returns old
  744.                                                   state */
  745.  
  746.     // Segments and their sizes and actual loaded state (helps catch preloads)
  747.  
  748.     for (i = 0; i < pMaxSegNum; ++i)
  749.     {
  750.         (*gIsResidentSeg)[i] = FALSE;
  751.         seg = GetSegResource(i + 1);
  752.         (*gCodeSegs)[i] = seg;
  753.         if (seg)                                // seg is non-nil if the segment number
  754.             (*pSegSize)[i] = SizeResource(seg);
  755.         else
  756.             (*pSegSize)[i] = 0;
  757.  
  758.         (*gIsLoadedSeg)[i] = TRUE;                // Assume all segments are loaded
  759.     }
  760.  
  761.     SetResLoad(oldResLoad);
  762.     //###########################################
  763.  
  764.     mainSegment = GetSegNumber((ProcPtr) & InitUMemory);// Main is always resident 
  765.     (*gIsResidentSeg)[mainSegment - 1] = TRUE;
  766.  
  767.     utilitySegment = GetSegNumber((ProcPtr) & UnloadAllSegments);// Utilities are always resident 
  768.     (*gIsResidentSeg)[utilitySegment - 1] = TRUE;
  769.  
  770.     if (qModelFarCode)
  771.         (*gIsResidentSeg)[pMaxSegNum - 1] = TRUE;// 32-bit bootstrap is always last
  772.     // _AND_ resident
  773.  
  774.     // init the gSysMemList 
  775.  
  776.     gSysMemList = (HandleListHandle)NewHandle(0);
  777.     FailNIL(gSysMemList);
  778.  
  779.     AddAllRsrc('LDEF', gSysMemList);
  780.     AddAllRsrc('CDEF', gSysMemList);
  781.     AddAllRsrc('MDEF', gSysMemList);
  782.     AddAllRsrc('WDEF', gSysMemList);
  783.     AddAllRsrc('PACK', gSysMemList);
  784.  
  785.     // Compute memory slop needed
  786.  
  787.     sizeTempReserve = 0;
  788.     sizeLowSpaceReserve = 0;
  789.     stackTot = 0;
  790.  
  791.     rsrcCnt = CountResources('seg!');
  792.     for (i = 1; i <= rsrcCnt; ++i)
  793.     {
  794.         h = GetIndResource('seg!', i);
  795.         sizeTempReserve += AddSegSizes(h);
  796.         ReleaseResource(h);
  797.     }
  798.  
  799.     rsrcCnt = CountResources('mem!');
  800.     for (i = 1; i <= rsrcCnt; ++i)
  801.     {
  802.         h = GetIndResource('mem!', i);
  803.         {
  804.             const Mem &memH = **((MemHandle)h);
  805.  
  806.             sizeTempReserve += memH.codeVal;
  807.             sizeLowSpaceReserve += memH.lowSpaceVal;
  808.             stackTot += memH.stackVal;
  809.         }
  810.         ReleaseResource(h);
  811.     }
  812.  
  813.     SetStackSpace(stackTot);
  814.  
  815.     MaxApplZone();
  816.  
  817.     gApp1MemList = NULL;
  818.     gApp2MemList = NULL;
  819. }
  820.  
  821. //--------------------------------------------------------------------------------------------------
  822. #pragma segment MAMemoryRes
  823.  
  824. pascal void FailNoReserve()
  825. {
  826.     if (!CheckReserve())
  827.         Failure(memFullErr, 0);
  828. }
  829.  
  830. //--------------------------------------------------------------------------------------------------
  831. #pragma segment MAMemoryRes
  832.  
  833. pascal void FailSpaceIsLow()
  834. {
  835. #if qDebug
  836.     MAName s;
  837.  
  838.     if (gAskFailure && CanReadLn())
  839.     {
  840.         GetCallersMethodName(s);
  841.         if (ReadYesNo("FailSpaceIsLow called by " + s + ".  Return true(Y or N) [N]? "))
  842.             Failure(memFullErr, 0);
  843.     }
  844. #endif
  845.  
  846.     if (MemSpaceIsLow())
  847.         Failure(memFullErr, 0);
  848. }
  849.  
  850. //--------------------------------------------------------------------------------------------------
  851. #pragma Push
  852. #if qTrace
  853. #pragma D+
  854. #endif
  855.  
  856. #pragma segment MAMemoryRes
  857.  
  858. pascal void GetReserveSize(Size &szCodeReserve,
  859.                            Size &szMemReserve)
  860. {
  861.     szCodeReserve = pSzCodeReserve;
  862.     szMemReserve = pSzMemReserve;
  863. }
  864. #pragma Pop
  865.  
  866. //--------------------------------------------------------------------------------------------------
  867. #pragma Push
  868. #if qTrace
  869. #pragma D+
  870. #endif
  871.  
  872. /* no %_BP/%_EP allowed in here, because we
  873.   cannot call to any other segment from this
  874.   procedure */
  875. #pragma segment MAMemoryRes
  876. // Shouldn't be unloaded 
  877.  
  878. pascal short GetSegFromPC(long ppc)
  879. {
  880.     long pc, 
  881.     segStart;
  882.     short i;
  883.     Handle seg;
  884.  
  885.     pc = *((LongIntPtr)ppc);
  886.  
  887.     /* Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs == NULL
  888.       before using it. */
  889.  
  890.     if (gCodeSegs)
  891.         for (i = 0; i < pMaxSegNum; ++i)
  892.         {
  893.             seg = (*gCodeSegs)[i];                // get segment handle 
  894.             if ((seg) &&!IsHandlePurged(seg))    // it's in memory 
  895.             {
  896.                 segStart = StripLong(*seg);        // get segment start 
  897.                 if ((pc >= segStart) && (pc < segStart + (*pSegSize)[i]))
  898.                     return i + 1;
  899.             }
  900.         }
  901.  
  902.     return 0;                                    // default return
  903. }
  904. #pragma Pop
  905.  
  906. //--------------------------------------------------------------------------------------------------
  907. #pragma Push
  908. #if qTrace
  909. #pragma D+
  910. #endif
  911.  
  912. /* no %_BP/%_EP allowed in here, because we
  913.   cannot call to any other segment from this
  914.   procedure */
  915.  
  916. #pragma segment MAMemoryRes
  917. /* must be in Main segment because we call
  918.   this in order to make the resident segment resident */
  919.  
  920. pascal short GetSegNumber(ProcPtr aProc)
  921. // Gets seg number from a Jump table address
  922. {
  923.     static const short kLoaded = 0x4EF9;        // if loaded then a JMP instruction 
  924.     static const short kUnLoaded = 0x3F3C;        // if unloaded then a LoadSeg trap
  925.  
  926.     if (*((IntegerPtr)aProc) == kLoaded)        // loaded segment 
  927.         return *((IntegerPtr)((long)aProc - 2));
  928.     else if (*((IntegerPtr)aProc) == kUnLoaded)    // unloaded segment 
  929.         return *((IntegerPtr)((long)aProc + 2));
  930.     else                                        /* routine that computed &proc was in same
  931.                                                   segment as the proc */
  932.         {
  933. #if qDebug
  934.         ProgramBreak("GetSegNumber was not passed an jump table address");
  935. #endif
  936.  
  937.         return 0;
  938.     }
  939. }
  940. #pragma Pop
  941.  
  942. //--------------------------------------------------------------------------------------------------
  943. #pragma segment MAMemoryRes
  944. #pragma Push
  945. #if qTrace
  946. #pragma D+
  947. #endif
  948.  
  949. pascal Size GetSegSize(short segNum)
  950. {
  951.     return (*pSegSize)[segNum - 1];
  952. }
  953. #pragma Pop
  954.  
  955. //--------------------------------------------------------------------------------------------------
  956. #pragma segment MAMemoryRes
  957. #pragma Push
  958. #if qTrace
  959. #pragma D+
  960. #endif
  961.  
  962. pascal long GrowZoneProc(Size)
  963. {
  964.     long result, 
  965.     reserveSize, 
  966.     OldA5;
  967.     Handle canPurge;
  968.     Size codeSize;
  969.  
  970.     OldA5 = SetCurrentA5();                        // Can be called from other worlds 
  971.  
  972.     result = 0;                                    // default is to fail 
  973.  
  974.     if (!pDuringGrowZone)                        // prevent re-entrancy 
  975.     {
  976.         pDuringGrowZone = TRUE;
  977.  
  978.         // on a temp alloc, free all code slack immediately 
  979.  
  980.         if (!pPermAllocation && IsHandleEligible(pCodeReserve))
  981.         {
  982.             EmptyHandle(pCodeReserve);
  983.             pReserveExists = FALSE;
  984.             result = 1;
  985.         }
  986.  
  987.         if (result == 0)                        /* try harder: see if we can purge a code
  988.                                                   segment or reduce the code reserve handle
  989.                                                 */
  990.         {
  991.             // compute size of resources currently in memory 
  992.  
  993.             codeSize = TotalTempSize(FALSE, canPurge);
  994.  
  995.             // see if the code reserve handle is too large 
  996.  
  997.             if (IsHandleEligible(pCodeReserve))
  998.             /* we have a code reserve handle; this implies permanent allocation,
  999.               otherwise the handle would have been emptied above */
  1000.             {
  1001.                 reserveSize = GetHandleSize(pCodeReserve);
  1002.  
  1003.                 /* the following test is an optimization to avoid calling
  1004.                   BuildCodeReserve if there is no hope of reducing
  1005.                   the code reserve handle */
  1006.  
  1007.                 if (codeSize + reserveSize + 8 > pSzCodeReserve)
  1008.                 {
  1009.                     // reserve is too big 
  1010.                     pReserveExists = FALSE;
  1011.                     // this should lower the code reserve 
  1012.                     BuildCodeReserve(reserveSize, TRUE);
  1013.  
  1014.                     // see if we succeeded in freeing some memory 
  1015.                     if (IsHandlePurged(pCodeReserve))
  1016.                         result = 1;
  1017.                     else if (GetHandleSize(pCodeReserve) < reserveSize)
  1018.                         result = 1;
  1019.                 }
  1020.             }
  1021.  
  1022.             if ((result == 0) && (canPurge) && (!pPermAllocation || IsHandlePurged(pCodeReserve)))/* got something; only purge it if this is
  1023.                                                   temporary || we know there is too much
  1024.                                                   code in memory already */
  1025.             {
  1026.                 if (gGZPurgeNotify)
  1027.                     CallNotify(canPurge, gGZPurgeNotify);
  1028.  
  1029.                 reserveSize = GetHandleSize(canPurge);
  1030.                 HPurge(canPurge);
  1031.                 EmptyHandle(canPurge);
  1032.                 pReserveExists = FALSE;
  1033.  
  1034.                 if (pPermAllocation)            // don't free too much however 
  1035.                     BuildCodeReserve(reserveSize, TRUE);
  1036.  
  1037.                 result = 1;
  1038.             }
  1039.         }
  1040.  
  1041.         if ((result == 0) && IsHandleEligible(pMemReserve))/* last ditch attempt-free emergency
  1042.                                                   reserve*/
  1043.         {
  1044.             EmptyHandle(pMemReserve);
  1045.             result = 1;
  1046.         }
  1047.  
  1048.         pDuringGrowZone = FALSE;
  1049.     }
  1050.  
  1051.     OldA5 = SetA5(OldA5);
  1052.  
  1053.     return result;
  1054. }
  1055. #pragma Pop
  1056.  
  1057. //--------------------------------------------------------------------------------------------------
  1058. #pragma segment MAMemoryRes
  1059. // Must be in same segment as grow zone proc
  1060. #pragma Push
  1061. #if qTrace
  1062. #pragma D+
  1063. #endif
  1064.  
  1065. void InstallGrowZoneProc()
  1066. /* Once called the grow zone proc's segment CAN!be moved since we're passing a NON-JT address
  1067.   to SetGrowZone (so we can be called from "other worlds" */
  1068. {
  1069.     THz aZone;
  1070.  
  1071.     pDuringGrowZone = FALSE;
  1072.     aZone = ApplicZone();
  1073.     aZone->flags |= 0x0400;
  1074.  
  1075.     /* set the Memory Manager bit that says to always call the
  1076.       Grow Zone proc, even in "non-critical" situations */
  1077.  
  1078.     SetGrowZone(&GrowZoneProc);
  1079. }
  1080. #pragma Pop
  1081.  
  1082. //--------------------------------------------------------------------------------------------------
  1083. #pragma Push
  1084. #if qTrace
  1085. #pragma D+
  1086. #endif
  1087.  
  1088. #pragma segment MAMemoryRes
  1089.  
  1090. pascal short PreloadHandler(RTState* state)
  1091.  
  1092. {
  1093.     LoadMacAppSegment(state->fSegNo);
  1094.  
  1095.     if (oldPreLoadHandler)
  1096.         return CallHandler(state, oldPreLoadHandler);
  1097.     else
  1098.         return 0;
  1099. }
  1100. #pragma Pop
  1101.  
  1102. //--------------------------------------------------------------------------------------------------
  1103. #pragma Push
  1104. #if qTrace
  1105. #pragma D+
  1106. #endif
  1107.  
  1108. /* no %_BP/%_EP allowed in here, because we
  1109.   cannot call to any other segment from this
  1110.   procedure */
  1111. #pragma Z+
  1112. #pragma segment MAMemoryRes
  1113. // must be in Main segment 
  1114.  
  1115. pascal void PostLoadMacAppSegment()
  1116. {
  1117.     long A5RegisterOnEntry = SetCurrentA5();            // ***** Called from trap patches *****
  1118.     // test if called from our application… if so, don't do patch behaviour. Thank you McSink! 
  1119.     if (GetA5() == A5RegisterOnEntry && pLoadSegCalledFromOwnApp)
  1120.         MAUseResFile(pOldResFile);        // Called back from our glue.  Restores current res file pointer. 
  1121.     SetA5(A5RegisterOnEntry);
  1122. }
  1123. #pragma Pop
  1124.  
  1125. //--------------------------------------------------------------------------------------------------
  1126. #pragma Push
  1127. #if qTrace
  1128. #pragma D+
  1129. #endif
  1130.  
  1131. #pragma segment MAMemoryRes
  1132.  
  1133. pascal short PostloadHandler(RTState* state)
  1134.  
  1135. {
  1136.     PostLoadMacAppSegment();
  1137.     if (oldPostLoadHandler)
  1138.         return CallHandler(state, oldPostLoadHandler);
  1139.     else
  1140.         return 0;
  1141. }
  1142. #pragma Pop
  1143.  
  1144. //--------------------------------------------------------------------------------------------------
  1145. #pragma segment Main
  1146. // Must be in main segment and called from main segment
  1147.  
  1148. pascal void InitUMemory()
  1149. {
  1150.  
  1151.     Size codeRes,  lowSpaceRes = 0;
  1152.     Handle miniInitSeg;
  1153.  
  1154.     /* Get these segments out of the way so that when DoInitUMemory gets called and the next
  1155.       block of master pointers gets allocated they won't constipate the heap */
  1156.  
  1157.     miniInitSeg = GetResource(kCode, GetSegNumber((ProcPtr) & DoInitUMemory));
  1158.     if (miniInitSeg)
  1159.     {
  1160.         UnloadSeg(&DoInitUMemory);
  1161.         LockHandleHigh(miniInitSeg);
  1162.     }
  1163.  
  1164.     DoInitUMemory(codeRes, lowSpaceRes);
  1165.  
  1166.     UnloadAllSegments();                        /* get init segment(s) out of middle of heap,
  1167.                                                   so SetReserveSize has maximum space to
  1168.                                                   work with */
  1169.  
  1170.     if (miniInitSeg)                            /* Yes, this would eventually get purged if
  1171.                                                   the space was needed badly enough, but
  1172.                                                   that happens very late in the game and can
  1173.                                                   confound the unwary */
  1174.         EmptyHandle(miniInitSeg);
  1175.  
  1176.     InstallGrowZoneProc();
  1177.  
  1178.     SetReserveSize(codeRes, lowSpaceRes);
  1179.     if (!pOKCodeReserve)                        /* couldn't get code reserve. Can't continue */
  1180.         Failure(memFullErr, 0);
  1181.     else
  1182.         {
  1183.         // Set up the LoadSeg patch 
  1184.  
  1185.         if (qModelFarCode)                        // Use the cool new RTLib so graciously
  1186.         // provided by Landon and Sandra
  1187.         {
  1188.             RTPB anRTPB;
  1189.             
  1190.             // Install the preload handler
  1191.             anRTPB.fOperation = kRTSetPreLoad;
  1192.             anRTPB.fUserHdlr = PreloadHandler;
  1193.             if (Runtime(&anRTPB) != noErr)
  1194.                 Failure(minErr, 0);                // !!! need to assign a code someday
  1195.             oldPreLoadHandler = anRTPB.fOldUserHdlr;
  1196.  
  1197.             // Install the postload handler
  1198.             anRTPB.fOperation = kRTSetPostLoad;
  1199.             anRTPB.fUserHdlr = PostloadHandler;
  1200.             if (Runtime(&anRTPB) != noErr)
  1201.                 Failure(minErr, 0);                    //!!! need to assign a code someday
  1202.             oldPostLoadHandler = anRTPB.fOldUserHdlr;
  1203.  
  1204.             pSegLoadPatch.OldTrapAddr = NGetTrapAddress(_LoadSeg, GetTrapType(_LoadSeg));
  1205.         }
  1206.         else
  1207.             FailOSErr(PatchTrap(pSegLoadPatch, _LoadSeg, (Ptr) & ALoadMacAppSeg));
  1208.     }
  1209. }
  1210.  
  1211.  
  1212.  
  1213. //--------------------------------------------------------------------------------------------------
  1214. #pragma Push
  1215. #if qTrace
  1216. #pragma D+
  1217. #endif
  1218.  
  1219. /* no %_BP/%_EP allowed in here, because we
  1220.   cannot call to any other segment from this
  1221.   procedure */
  1222.  
  1223. #pragma segment MAMemoryRes
  1224. // must be in Main segment 
  1225.  
  1226. pascal long LoadMacAppSegment(short segNum)
  1227. {
  1228. #if qDebug
  1229.     short id;
  1230.     ResType kind;
  1231.     Str255 segName;
  1232.     MAName s;
  1233.     Handle seg;
  1234. #endif
  1235.  
  1236.     long A5RegisterOnEntry;
  1237.     long loadMacAppSegment;
  1238.  
  1239.     A5RegisterOnEntry = SetCurrentA5();            // ***** Called from trap patches *****
  1240.  
  1241.     loadMacAppSegment = pSegLoadPatch.oldTrapAddr;// Where to go next 
  1242.  
  1243.     if (GetA5() != A5RegisterOnEntry)
  1244.     {
  1245.         // not called from our application… don't do patch behaviour. Thank you McSink! 
  1246.         pLoadSegCalledFromOwnApp = FALSE;
  1247.         SetA5(A5RegisterOnEntry);
  1248.     }
  1249.     else
  1250.         {
  1251.         pLoadSegCalledFromOwnApp = TRUE;
  1252.         pOldResFile = MAUseResFile(gCodeRefNum);/* Must set a global because we return from
  1253.                                                   this function and then forward to the
  1254.                                                   actual segment loader which should also be
  1255.                                                   pointing to the _now_ correct resfile.
  1256.                                                   When we get called back again in
  1257.                                                   PostLoadMacAppSegment we will restore the
  1258.                                                   old resFile as the current resFile. Sorry
  1259.                                                   about the global. */
  1260.  
  1261. #if qDebug
  1262.         if (!GetResLoad())
  1263.         {
  1264.             SetResLoad(TRUE);
  1265.             ProgramBreak("Whoops… LoadSeg called with resload set false");
  1266.             Failure(minErr, 0);                    /*??? Assign an error code someday or
  1267.                                                   setresload to true ???*/
  1268.         }
  1269.  
  1270. #endif
  1271.  
  1272.         if (!PreloadSegmentResource(segNum))
  1273.         {
  1274. #if qDebug
  1275.             GetCallersMethodName(s);
  1276.             SetResLoad(FALSE);
  1277.             seg = MAGet1Resource(kCode, segNum);
  1278.  
  1279.             GetResInfo(seg, id, kind, segName);
  1280.             SetResLoad(TRUE);
  1281. //###SRF            ProgramBreak("In " + s + form(" couldn''t load segment: %d", segNum) + segName);
  1282. #endif
  1283.  
  1284.             Failure(memFullErr, 0);
  1285.         }
  1286.  
  1287.         (*gIsLoadedSeg)[segNum - 1] = TRUE;
  1288.  
  1289. #if qDebug
  1290.         if (gSegReport)
  1291.         {
  1292.             // Cause the debugger to break at the start of the next routine. 
  1293.             gReportNext = TRUE;
  1294.             GetResInfo((*gCodeSegs)[segNum - 1], id, kind, segName);
  1295. //###SRF            gReportInfo = form("  *** Segment Loaded: %d ", segNum) + segName;
  1296.             gSingleStep = gMemMgtBreak;
  1297.         }
  1298. #endif
  1299.  
  1300.     }
  1301.  
  1302.     return loadMacAppSegment;
  1303. }
  1304. #pragma Pop
  1305.  
  1306. //--------------------------------------------------------------------------------------------------
  1307. #pragma segment MAMemoryRes
  1308. // Must be in Main segment 
  1309.  
  1310. pascal void LoadResidentSegments()
  1311. {
  1312.     short offset, 
  1313.     segNumber, 
  1314.     rsrcCnt;
  1315.     Handle nameList,  seg;
  1316.     SignedBytePtr p;
  1317.     Str255 name;
  1318.     ResType theType;
  1319.     char savedState;
  1320.  
  1321.     rsrcCnt = CountResources('res!');
  1322.     for (short resIndex = 1; resIndex <= rsrcCnt; ++resIndex)
  1323.     {
  1324.         nameList = GetIndResource('res!', resIndex);
  1325.         savedState = HGetState(nameList);
  1326.         HLock(nameList);                        // lock it down for BlockMove
  1327.  
  1328.         offset = 2;
  1329.         for (short i = 1; i <= *((IntegerPtr) * nameList); ++i)
  1330.         {
  1331.             p = (SignedBytePtr)(*nameList + offset);
  1332.             BlockMove((Ptr)p, (Ptr) & name, *p + 1);
  1333.             offset += name.Length() + 1;
  1334.  
  1335.             seg = MAGet1NamedResource(kCode, name);
  1336.  
  1337.             if (seg)
  1338.             {
  1339.                 GetResInfo(seg, segNumber, theType, name);
  1340.                 SetResidentSegment(segNumber, TRUE);
  1341.             }
  1342.         }
  1343.  
  1344.         HSetState(nameList, savedState);
  1345.         ReleaseResource(nameList);
  1346.     }
  1347. }
  1348.  
  1349. //--------------------------------------------------------------------------------------------------
  1350. #pragma segment MAMemoryRes
  1351.  
  1352. pascal Boolean MemSpaceIsLow()
  1353. {
  1354.     BuildAllReserves();
  1355.     return IsHandlePurged(pMemReserve);
  1356. }
  1357.  
  1358. //--------------------------------------------------------------------------------------------------
  1359. #pragma segment MAMemoryRes
  1360.  
  1361. pascal Handle NewPermHandle(Size logicalSize)
  1362. {
  1363.     static const short initVal = 0xF3;            // odd at all byte boundaries            
  1364.  
  1365.     Boolean priorPerm;
  1366.     Handle aHandle;
  1367.  
  1368.     priorPerm = PermAllocation(TRUE);
  1369.     aHandle = NewHandle(logicalSize);
  1370.     pPermAllocation = priorPerm;
  1371.     FailNIL(aHandle);
  1372. #pragma Push
  1373. #pragma R-
  1374.     if (qDebug)
  1375.         BlockSet(*aHandle, logicalSize, initVal);
  1376. #pragma Pop
  1377.     return aHandle;
  1378. }
  1379.  
  1380. //--------------------------------------------------------------------------------------------------
  1381. #pragma segment MAMemoryRes
  1382.  
  1383. pascal Ptr NewPermPtr(Size logicalSize)
  1384. {
  1385.     static const short initVal = 0xF3;            // odd at all byte boundaries            
  1386.  
  1387.     Boolean priorPerm;
  1388.     Ptr aPtr;
  1389.  
  1390.  
  1391.     priorPerm = PermAllocation(TRUE);
  1392.     aPtr = NewPtr(logicalSize);
  1393.     pPermAllocation = priorPerm;
  1394.     FailNIL(aPtr);
  1395. #pragma Push
  1396. #pragma R-
  1397.     if (qDebug)
  1398.         BlockSet(aPtr, logicalSize, initVal);
  1399. #pragma Pop
  1400.     return aPtr;
  1401. }
  1402.  
  1403. //--------------------------------------------------------------------------------------------------
  1404. #pragma Push
  1405. #if qTrace
  1406. #pragma D+
  1407. #endif
  1408.  
  1409. #pragma segment MAMemoryRes
  1410.  
  1411. pascal Boolean PermAllocation(Boolean permanent)
  1412. {
  1413.     Boolean permAllocation = pPermAllocation;
  1414.  
  1415.     if (permanent != pPermAllocation)
  1416.     {
  1417.         pPermAllocation = permanent;
  1418.         if (permanent)
  1419.             BuildCodeReserve(kGZMaxAlloc, FALSE);
  1420.     }
  1421.  
  1422.     return permAllocation;
  1423. }
  1424. #pragma Pop
  1425.  
  1426. //--------------------------------------------------------------------------------------------------
  1427. #pragma Push
  1428. #if qTrace
  1429. #pragma D+
  1430. #endif
  1431.  
  1432. /* no %_BP/%_EP allowed in here, because we
  1433.   cannot call to any other segment from this
  1434.   procedure */
  1435. // must be in Main segment 
  1436. #pragma segment MAMemoryRes
  1437.  
  1438. class CWithCodeResFileDo
  1439. {
  1440.     short &fSegNum;
  1441.     Handle &fSeg;
  1442. public:
  1443.     CWithCodeResFileDo(short &segNum,
  1444.                        Handle &seg)
  1445.         :
  1446.         fSegNum(segNum),
  1447.           fSeg(seg)
  1448.         {
  1449.         }
  1450.  
  1451.     pascal void DoGetSegHandle();
  1452. };
  1453.  
  1454. #pragma segment MAMemoryRes
  1455. // must be in Main segment 
  1456.  
  1457. pascal void CWithCodeResFileDo::DoGetSegHandle()
  1458. {
  1459.     fSeg = Get1Resource(kCode, fSegNum);
  1460. }
  1461.  
  1462. #pragma segment MAMemoryRes
  1463. // must be in Main segment 
  1464.  
  1465. pascal Boolean PreloadSegmentResource(short segNum)
  1466. {
  1467.     Handle seg;
  1468.     CWithCodeResFileDo scopeLink(segNum, seg);
  1469.  
  1470.     if (qDebug && pPermAllocation)
  1471.     {
  1472.         fprintf(stderr, "segment # = %d", segNum);
  1473.         ProgramBreak("Trying to load a segment with PermAllocation == true.");
  1474.     }
  1475.  
  1476.     WithCodeResFileDo((DoWithResFileType) & CWithCodeResFileDo::DoGetSegHandle, &scopeLink);
  1477.  
  1478.     if (!seg)
  1479.         return FALSE;
  1480.     else
  1481.         {
  1482.         if (!IsHandleLocked(seg))                // not yet locked 
  1483.             LockHandleHigh(seg);
  1484.         return TRUE;
  1485.     }
  1486. }
  1487. #pragma Pop
  1488.  
  1489. //--------------------------------------------------------------------------------------------------
  1490. #pragma segment MAMemoryRes
  1491.  
  1492. pascal void RemHandle(Handle h,
  1493.                       HandleListHandle toList)
  1494. {
  1495.     long p, 
  1496.     maxP, 
  1497.     offset;
  1498.  
  1499.     p = (long) * toList;                        // Address of first element 
  1500.     maxP = p + GetHandleSize((Handle)toList);    // Address past last element 
  1501.  
  1502.     // Skip elements until item is found 
  1503.     while ((p < maxP) && *((LongIntPtr)p) != (long)h)
  1504.         p += sizeof(Handle);
  1505.  
  1506.     if (p < maxP)                                // Item was found 
  1507.     {
  1508.         offset = Munger((Handle)toList, p - (long) * toList, NULL, sizeof(Handle), (Ptr) & h, 0);
  1509.         FailMemError();
  1510.     }
  1511. }
  1512.  
  1513. //--------------------------------------------------------------------------------------------------
  1514. #pragma segment MAMemoryRes
  1515. #pragma Push
  1516. #if qTrace
  1517. #pragma D+
  1518. #endif
  1519.  
  1520. typedef Handle *HandlePtr;
  1521.  
  1522. void ScanList(HandleListHandle list,
  1523.                      DoToHandlesType DoToHandle,
  1524.                      void *scopeLink)
  1525. {
  1526.     HandlePtr p = (HandlePtr) * list;
  1527.  
  1528.     for (short i = (short)(GetHandleSize((Handle)list) / sizeof(Handle)); i > 0; --i, ++p)
  1529.         DoToHandle(*p, scopeLink);
  1530. }
  1531.  
  1532.  
  1533. pascal void ScanHandles(DoToHandlesType DoToHandle,
  1534.                         void *scopeLink)
  1535. {
  1536.     ScanList(gCodeSegs, DoToHandle, scopeLink);
  1537.     if (gApp1MemList)
  1538.         ScanList(gApp1MemList, DoToHandle, scopeLink);
  1539.     ScanList(gSysMemList, DoToHandle, scopeLink);
  1540.     if (gApp2MemList)
  1541.         ScanList(gApp2MemList, DoToHandle, scopeLink);
  1542. }
  1543. #pragma Pop
  1544.  
  1545. //--------------------------------------------------------------------------------------------------
  1546. #pragma segment MAMemoryRes
  1547.  
  1548. pascal void SetPermHandleSize(Handle h,
  1549.                               Size newSize)
  1550. {
  1551.     static const short initVal = 0xF3;
  1552.  
  1553.     Boolean priorPerm;
  1554. #if qDebug
  1555.     Size oldSize;
  1556. #endif
  1557.  
  1558.     priorPerm = PermAllocation(TRUE);
  1559. #if qDebug
  1560.     oldSize = GetHandleSize(h);
  1561. #endif
  1562.  
  1563.     SetHandleSize(h, newSize);
  1564.     pPermAllocation = priorPerm;                /* Since we are in the memory unit we can
  1565.                                                   break the encapsulation of the
  1566.                                                   PermAllocation Call to just set the
  1567.                                                   pPermAllocation flag back directly. This
  1568.                                                   lets us be assured that no operations have
  1569.                                                   occurred that would invalidate the MemErr
  1570.                                                   flag… thus the following call will give a
  1571.                                                   true result*/
  1572.     FailMemError();
  1573. #if qDebug
  1574. #pragma Push
  1575. #pragma R-
  1576.     if (oldSize < newSize)
  1577.         BlockSet((Ptr) * h + oldSize, newSize - oldSize, initVal);
  1578. #pragma Pop
  1579. #endif
  1580.  
  1581. }
  1582.  
  1583. //--------------------------------------------------------------------------------------------------
  1584. #pragma segment MAMemoryRes
  1585.  
  1586. pascal void SetPermPtrSize(Ptr p,
  1587.                            Size newSize)
  1588. {
  1589.     static const short initVal = 0xF5;
  1590.  
  1591.     Boolean priorPerm;
  1592. #if qDebug
  1593.     Size oldSize;
  1594. #endif
  1595.  
  1596.     priorPerm = PermAllocation(TRUE);
  1597. #if qDebug
  1598.     oldSize = GetPtrSize(p);
  1599. #endif
  1600.  
  1601.     SetPtrSize(p, newSize);
  1602.     pPermAllocation = priorPerm;                /* Since we are in the memory unit we can
  1603.                                                   break the encapsulation of the
  1604.                                                   PermAllocation Call to just set the
  1605.                                                   pPermAllocation flag back directly. This
  1606.                                                   lets us be assured that no operations have
  1607.                                                   occurred that would invalidate the MemErr
  1608.                                                   flag… thus the following call will give a
  1609.                                                   true result*/
  1610.     FailMemError();
  1611. #if qDebug
  1612. #pragma Push
  1613. #pragma R-
  1614.     if (oldSize < newSize)
  1615.         BlockSet((Ptr)p + oldSize, newSize - oldSize, initVal);
  1616. #pragma Pop
  1617. #endif
  1618.  
  1619. }
  1620.  
  1621. //--------------------------------------------------------------------------------------------------
  1622. #pragma segment MAMemoryRes
  1623.  
  1624. pascal void SetReserveSize(Size forCode,
  1625.                            Size forOther)
  1626. {
  1627.     pSzCodeReserve = forCode;
  1628.     pSzMemReserve = forOther;
  1629.  
  1630.     // Since the numbers have changed, make sure we start from scratch. 
  1631.     pReserveExists = FALSE;
  1632.     EmptyHandle(pMemReserve);
  1633.  
  1634.     BuildAllReserves();
  1635. }
  1636.  
  1637. //--------------------------------------------------------------------------------------------------
  1638. #pragma Push
  1639. #if qTrace
  1640. #pragma D+
  1641. #endif
  1642.  
  1643. /* no %_BP/%_EP allowed in here, because we
  1644.   cannot call to any other segment from this
  1645.   procedure */
  1646. #pragma segment MAMemoryRes
  1647. // must be in Main segment 
  1648.  
  1649. pascal void SetResidentSegment(short segNum,
  1650.                                Boolean makeResident)
  1651. {
  1652. #if qDebug
  1653.     short id;
  1654.     ResType kind;
  1655.     Str255 segName;
  1656.     MAName s;
  1657.     Handle seg;
  1658. #endif
  1659.  
  1660.     if (makeResident)
  1661.     {
  1662.         (*gIsResidentSeg)[segNum - 1] = TRUE;
  1663.         if (!PreloadSegment(segNum))
  1664.         {
  1665. #if qDebug
  1666.             GetCallersMethodName(s);
  1667.             SetResLoad(FALSE);
  1668.             seg = MAGet1Resource(kCode, segNum);
  1669.             SetResLoad(TRUE);
  1670.             GetResInfo(seg, id, kind, segName);
  1671. //###SRF            ProgramBreak("In " + s + form(" couldn''t load segment: %d", segNum) + segName);
  1672. #endif
  1673.  
  1674.             Failure(memFullErr, 0);
  1675.         }
  1676.     }
  1677.     else
  1678.         (*gIsResidentSeg)[segNum - 1] = FALSE;
  1679. }
  1680. #pragma Pop
  1681.  
  1682. //--------------------------------------------------------------------------------------------------
  1683. #pragma segment MAMiniInit
  1684.  
  1685. pascal void SetStackSpace(long numBytes)
  1686. {
  1687.     long newLimit;
  1688.  
  1689.     newLimit = (long)GetCurStackBase() - numBytes;
  1690.     if ((long)GetApplLimit() > newLimit)
  1691.         SetApplLimit((Ptr)newLimit);
  1692. }
  1693.  
  1694. //--------------------------------------------------------------------------------------------------
  1695. #pragma segment MAMemoryRes
  1696. #pragma Push
  1697. #if qTrace
  1698. #pragma D+
  1699. #endif
  1700.  
  1701. class CTotalTempSize
  1702. {
  1703.     Boolean &fJustLocked;
  1704.     Handle &fCanPurge;
  1705.     Size &fTotal;
  1706.     THz &fApplZone;
  1707. public:
  1708.     CTotalTempSize(Boolean &justLocked,
  1709.                    Handle &canPurge,
  1710.                    Size &total,
  1711.                    THz &applZone)
  1712.         :
  1713.         fJustLocked(justLocked),
  1714.           fCanPurge(canPurge),
  1715.           fTotal(total),
  1716.           fApplZone(applZone)
  1717.         {
  1718.         }
  1719.  
  1720.     pascal void TotalUp(Handle h);
  1721. };
  1722.  
  1723. #pragma segment MAMemoryRes
  1724.  
  1725. pascal void CTotalTempSize::TotalUp(Handle h)
  1726. {
  1727.     Boolean hIsLocked;
  1728.  
  1729.     if (!IsHandlePurged(h))                        // in memory already 
  1730.         if (HandleZone(h) == fApplZone)            // in application heap 
  1731.         {
  1732.             HNoPurge(h);
  1733.  
  1734.             hIsLocked = IsHandleLocked(h);
  1735.  
  1736.             if (!fJustLocked || hIsLocked)
  1737.                 fTotal += GetHandleSize(h) + 8;
  1738.             // add in the size plus heap overhead 
  1739.  
  1740.             if (!hIsLocked)
  1741.                 if (fCanPurge == NULL)
  1742.                     if (IsHandleEligible(h))
  1743.                         fCanPurge = h;
  1744.         }
  1745. }
  1746.  
  1747. #pragma segment MAMemoryRes
  1748.  
  1749. pascal Size TotalTempSize(Boolean justLocked,
  1750.                           Handle &canPurge)
  1751. {
  1752.     Size total;
  1753.     THz applZone;
  1754.     CTotalTempSize scopeLink(justLocked, canPurge, total, applZone);
  1755.  
  1756.     canPurge = NULL;
  1757.     total = 0;
  1758.     applZone = ApplicZone();
  1759.  
  1760.     ScanHandles((DoToHandlesType) & CTotalTempSize::TotalUp, &scopeLink);
  1761.  
  1762.     return total;
  1763. }
  1764. #pragma Pop
  1765.  
  1766. //--------------------------------------------------------------------------------------------------
  1767. #pragma segment MAMemoryRes
  1768. #pragma Push
  1769. #if qTrace
  1770. #pragma D+
  1771. #endif
  1772.  
  1773. pascal void WithCodeResFileDo(DoWithResFileType DoWithResFile,
  1774.                               void *scopeLink)
  1775. {
  1776.     short oldResFile = MAUseResFile(gCodeRefNum);
  1777.  
  1778.     DoWithResFile(scopeLink);
  1779.  
  1780.     MAUseResFile(oldResFile);
  1781. }
  1782. #pragma Pop
  1783.  
  1784. //--------------------------------------------------------------------------------------------------
  1785. #pragma Push
  1786. #if qTrace
  1787. #pragma D+
  1788. #endif
  1789.  
  1790. /* no %_BP/%_EP allowed in here, because we
  1791.   cannot call to any other segment from this
  1792.   procedure */
  1793. #pragma segment MAMemoryRes
  1794. // must be in Main segment 
  1795.  
  1796. class CUnloadAllSegments
  1797. {
  1798.     long &jmpTablePtr;
  1799. public:
  1800.     CUnloadAllSegments(long &aJmpTablePtr)
  1801.         :
  1802.         jmpTablePtr(aJmpTablePtr)
  1803.         {}
  1804.  
  1805. #if qDebug
  1806.     pascal void DoToFrame(long,
  1807.                           long ppc,
  1808.                           long,
  1809.                           long);
  1810. #endif
  1811.  
  1812.     pascal void UnloadEm();
  1813. };
  1814.  
  1815. #if qDebug
  1816. #pragma segment MAMemoryRes
  1817. // must be in Main segment 
  1818.  
  1819. pascal void CUnloadAllSegments::DoToFrame(long,
  1820.                                           long ppc,
  1821.                                           long,
  1822.                                           long)
  1823. {
  1824.     short itsSeg = GetSegFromPC(ppc);
  1825.     if ((itsSeg != 0) &&!(*gIsResidentSeg)[itsSeg - 1] && (*gIsLoadedSeg)[itsSeg - 1])
  1826.     {
  1827.         fprintf(stderr, "Segment#: %d", itsSeg);
  1828.         ProgramBreak("I really don''t think that you want to unload a segment into which you are going to return!");
  1829.     }
  1830. }
  1831. #endif
  1832.  
  1833. #pragma segment MAMemoryRes
  1834. // must be in Main segment 
  1835.  
  1836. struct ModelFarCodeHeader
  1837. {
  1838.     short field1;
  1839.     short field2;
  1840.     long A5OffsetOf16BitEntries;
  1841.     long numOf16BitEntries;
  1842.     long A5OffsetOf32BitEntries;
  1843.     long numOf32BitEntries;
  1844.     char otherEvenMorePrivateStuff;            // You didn't think I would reveal any more than I had to… 
  1845.     // did you?
  1846. };
  1847.  
  1848. typedef ModelFarCodeHeader *ModelFarCodeHeaderPtr,
  1849.  **ModelFarCodeHeaderHandle;
  1850. const short kJTSkipOver = 2;                    /*  size of jmp (or loadseg) instruction that
  1851.                                                   must be skipped in the JT Entry in order
  1852.                                                   to get to the target address */
  1853.  
  1854. pascal void CUnloadAllSegments::UnloadEm()
  1855. {
  1856.     short i;
  1857.     Handle seg;
  1858.  
  1859.     for (i = 0; i < pMaxSegNum; ++i)
  1860.     {
  1861.         if (!(*gIsResidentSeg)[i] && (*gIsLoadedSeg)[i])
  1862.         {
  1863.             seg = (*gCodeSegs)[i];
  1864.             if ((seg) &&!IsHandlePurged(seg))
  1865.             {
  1866.                 // see the 32 B-E ERS (if you can find it)
  1867.                 if (qModelFarCode)
  1868.                 if ((*((ModelFarCodeHeaderHandle)seg))->numOf16BitEntries)
  1869.                     UnLoadSeg((Ptr)(jumpTablePtr + (*((ModelFarCodeHeaderHandle) seg))->
  1870.                                     A5OffsetOf16BitEntries + kJTSkipOver));
  1871.                 else                            // Has to be the other since we wouldn't even
  1872.                     // have a segment otherwise
  1873.                     UnLoadSeg((Ptr)(jumpTablePtr + (*((ModelFarCodeHeaderHandle)seg))->
  1874.                                     A5OffsetOf32BitEntries + kJTSkipOver));
  1875.                 else
  1876.                     UnloadSeg((Ptr)(jmpTablePtr + **((IntegerHandle)seg) + kJTSkipOver));
  1877.                 (*gIsLoadedSeg)[i] = FALSE;
  1878.             }
  1879.         }
  1880.     }
  1881. }
  1882.  
  1883.  
  1884. #pragma segment MAMemoryRes
  1885. // must be in Main segment 
  1886.  
  1887. pascal void UnloadAllSegments(void)
  1888. {
  1889. #if qDebug
  1890.     CheckRsrcUsage();
  1891. #endif
  1892.  
  1893.     if (gUnloadAllSegs)
  1894.     {
  1895.         long jmpTablePtr = (long) (GetA5() + GetCurJTOffset());
  1896.         CUnloadAllSegments localScope(jmpTablePtr);
  1897. #if qDebug
  1898.         EachFrameDo((long)GetCurStackFramePtr(), (long)(GetCurStackFramePtr() + 4), (DoToFrameType) & CUnloadAllSegments::
  1899.                     DoToFrame, &localScope);
  1900. #endif
  1901.  
  1902.         WithCodeResFileDo((DoWithResFileType) & CUnloadAllSegments::UnloadEm, &localScope);
  1903.  
  1904.         if (gSegReport)
  1905.             ProgramReport("  *** Just unloaded all segments ***", gMemMgtBreak);
  1906.     }
  1907. }
  1908. #pragma Pop
  1909.  
  1910. //--------------------------------------------------------------------------------------------------
  1911. #if qDebug
  1912. #pragma segment MADebug
  1913.  
  1914. pascal void WriteReserves()
  1915. /* WRITELN's the temporary reserve and low-memory reserves in the
  1916.   debug window. */
  1917.  
  1918. {
  1919.     WrLblPtr("Temporary reserve (pCodeReserve)", (long)pCodeReserve);
  1920.     fprintf(stderr, "\n");
  1921.     WrLblPtr("Low-memory reserve (pMemReserve)", (long)pMemReserve);
  1922.     fprintf(stderr, "\n");
  1923. }
  1924. #endif
  1925.  
  1926.  
  1927.